//
// Created by yangentao on 2019/10/28.
//

import Foundation

extension HttpResp {

    var ysonObject: YsonObject? {
        if let s = self.text {
            return Yson.parseObject(s)
        }
        return nil
    }
}

public extension HttpReq {
    @discardableResult
    static func +=(lhs: HttpReq, rhs: KeyAny) -> HttpReq {
        if let v = rhs.value ?? nil {
            lhs.arg(key: rhs.key, value: "\(v)")
        }
        return lhs
    }
}

public extension HttpPostRaw {
    func bodyJson(@AnyBuilder _ block: AnyBuildBlock) -> Self {
        let yo = yson(block)
        bodyJson(data: yo.yson.data(using: .utf8)!)
        return self
    }
}


public typealias DownCallback = (String, Bool) -> Void

public class FileDownloader: NSObject {
    var processSet: List<String> = List<String>()
    private var listenMap: Map<String, List<DownCallback>> = [:]
    private let taskQueue = TaskQueue("file_download")
    public static let inst: FileDownloader = FileDownloader()
}

public extension FileDownloader {

    func isDownloading(_ url: String) -> Bool {
        listenMap.contains(key: url)
    }

    func retrive(_ url: String, _ block: @escaping (AppFile?) -> Void) {
        let f = FileCache.getFile(key: url)
        if f != nil {
//            logd("use Cache! ", f?.size, f?.appPath)
            block(f)
            return
        }
//        logd("use Download...")
        self.download(url, block)
    }

    func download(_ url: String, _ block: @escaping (AppFile?) -> Void) {
        self.taskQueue.back {
            self.downSync(url) { u, ok in
                let f = FileCache.getFile(key: u)
                block(f)
            }
        }
    }

    private func downSync(_ url: String, _ callback: @escaping DownCallback) {
        let urlSet = self.processSet
        let urlMap = self.listenMap
        if let ls = urlMap[url] {
            ls.append(callback)
        } else {
            urlMap[url] = List<DownCallback>([callback])
        }
        if urlSet.contains(url) {
            return
        }
        urlSet.append(url)
        let filename = Date.tempFileName
        let file = FileCache.makeCacheFile(filename)
        let ok = httpDown(url, file)
        if ok {
            FileCache.put(key: url, file: file)
        } else {
            file.remove()
        }
        urlSet.remove(value: url)
        Task.fore {
            if let ls: List<DownCallback> = urlMap.remove(key: url) {
                for l in ls {
                    l(url, ok)
                }
            }
        }
    }

    private func httpDown(_ url: String, _ file: AppFile) -> Bool {
        guard let u = URL(string: url) else {
            return false
        }
        if url.count < 8 {
            return false
        }
        let r = HttpGet(url: u).requestSync()
        if !r.OK {
            return false
        }
        guard let data = r.content else {
            return false
        }
        file.writeData(data: data)
        return file.isFile
    }
}

